﻿/***************************
 * Author：peiyang
 * DateTime：
 * Description：<Description>
 * Copyright：臭皮匠工作室
 **/

using System;
using System.Net.NetworkInformation;

namespace Cpjit.SunnyPaine.Toolkit.Net.Generic
{
    /// <summary>
    /// 提供Ping命令工具。
    /// </summary>
    public class PingUtil
    {
        /// <summary>
        /// Ping指定的IP地址。
        /// </summary>
        /// <param name="ip">目标IP地址。</param>
        /// <param name="message">返回结果的消息。</param>
        /// <param name="timeout">响应超时时长。单位：毫秒。默认5秒。</param>
        /// <returns></returns>
        public static bool PingIP(string ip, ref string message, int timeout = 5000)
        {
            bool result = false;

            try
            {
                Ping pingSend = new Ping();
                PingReply pingReply = pingSend.Send(ip, timeout);
                switch (pingReply.Status)
                {
                    case IPStatus.Success:
                        result = true;
                        message = "ICMP 回送请求成功；收到一个 ICMP 回送答复。";
                        break;
                    case IPStatus.DestinationNetworkUnreachable:
                        message = "由于无法访问包含目标计算机的网络，ICMP 回送请求失败。";
                        break;
                    case IPStatus.DestinationHostUnreachable:
                        message = "由于无法访问目标计算机，ICMP 回送请求失败。";
                        break;
                    case IPStatus.DestinationProtocolUnreachable:
                        message = "由于无法访问 ICMP 回送消息中指定的目标计算机，ICMP 回送请求失败，这是因为目标计算机不支持数据包的协议。 此值仅适用于 IPv4。";
                        break;
                    case IPStatus.DestinationPortUnreachable:
                        message = "由于目标计算机上的端口不可用，ICMP 回送请求失败。";
                        break;
                    case IPStatus.NoResources:
                        message = "由于网络资源不足，ICMP 回送请求失败。";
                        break;
                    case IPStatus.BadOption:
                        message = "由于包含无效选项，ICMP 回送请求失败。";
                        break;
                    case IPStatus.HardwareError:
                        message = "由于硬件错误，ICMP 回送请求失败。";
                        break;
                    case IPStatus.PacketTooBig:
                        message = "由于包含请求的数据包的大小超过了位于源和目标之间的节点（路由器或网关）的最大传输单位 (MTU)，ICMP 回送请求失败。";
                        break;
                    case IPStatus.TimedOut:
                        message = "在所分配的时间内未收到 ICMP 回送答复。";
                        break;
                    case IPStatus.BadRoute:
                        message = "由于在源计算机和目标计算机之间没有有效的路由，ICMP 回送请求失败。";
                        break;
                    case IPStatus.TtlExpired:
                        message = "由于数据包的生存时间 (TTL) 值达到零，导致转发节点（路由器或网关）放弃数据包，ICMP 回送请求失败。";
                        break;
                    case IPStatus.TtlReassemblyTimeExceeded:
                        message = "由于数据包被分割为片段以便传输，但未在分配的时间内收到所有片段进行重组，ICMP 回送请求失败。";
                        break;
                    case IPStatus.ParameterProblem:
                        message = "由于节点（路由器或网关）在处理数据包标头时遇到问题，ICMP 回送请求失败。例如，当标头包含无效的字段数据或无法识别的选项时会出现这种状况。";
                        break;
                    case IPStatus.SourceQuench:
                        message = "由于已放弃数据包，ICMP 回送请求失败。 当源计算机的输出队列中没有足够的存储空间时，或者当数据包到达目标过快而无法进行处理时，就会发生这种情况。";
                        break;
                    case IPStatus.BadDestination:
                        message = "由于目标 IP 地址无法收到 ICMP 回送请求或者永远都不应当出现在任何 IP 数据报的目标地址字段中，ICMP 回送请求失败。";
                        break;
                    case IPStatus.DestinationUnreachable:
                        message = "由于无法访问 ICMP 回送消息中指定的目标计算机，ICMP 回送请求失败；此问题的确切原因未知。";
                        break;
                    case IPStatus.TimeExceeded:
                        message = "由于数据包的生存时间 (TTL) 值达到零，导致转发节点（路由器或网关）放弃数据包，ICMP 回送请求失败。";
                        break;
                    case IPStatus.BadHeader:
                        message = "由于标头无效，ICMP 回送请求失败。";
                        break;
                    case IPStatus.UnrecognizedNextHeader:
                        message = "由于“下一标头”字段中没有可识别的值，ICMP 回送请求失败。 “下一标头”字段指示扩展标头类型（如果存在）或者 IP 层上的协议（例如，TCP 或 UDP）。";
                        break;
                    case IPStatus.IcmpError:
                        message = "由于 ICMP 协议错误，ICMP 回送请求失败。";
                        break;
                    case IPStatus.DestinationScopeMismatch:
                        message = "由于 ICMP 回送消息中指定的源地址和目标地址不在同一范围内，ICMP 回送请求失败。 这通常是因路由器使用了源地址范围以外的接口转发数据包而导致的。";
                        break;
                    case IPStatus.Unknown:
                        message = "由于未知原因，ICMP 回送请求失败。";
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                message = ex.Message;
                result = false;
            }

            return result;
        }
    }
}